#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/socket.h>
#include <arpa/inet.h>

#define BUFFER_SIZE (200)
#define HEAD_SIZE (50) 

#define PORT (9090)
#define IP "127.0.0.1"

#define REPLY_HEAD "Server receive message: "


int main()
{
    int srv_socket;
    struct sockaddr_in srv_addr;
    struct sockaddr_in *ptr_srv_addr = &srv_addr;

    int clt_socket;
    struct sockaddr_in clt_addr;
    socklen_t clt_addr_size = sizeof(clt_addr);
    struct sockaddr_in *ptr_clt_addr = &clt_addr;

    char buffer[BUFFER_SIZE];
    char reply_buff[HEAD_SIZE+BUFFER_SIZE];
    char *ptr_reply_buff;
    int datalen;

    // Create socket.
    srv_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(0 > srv_socket)
    {
        printf("Create socket error!\n");
        exit(-1);
    }

    memset(ptr_srv_addr, 0, sizeof(srv_addr));
    srv_addr.sin_family = AF_INET;
    srv_addr.sin_addr.s_addr = inet_addr(IP);
    srv_addr.sin_port = htons(PORT);

    // Bind ip and port to socket.
    bind(srv_socket, ptr_srv_addr, sizeof(srv_addr));

    // Listen socket with max buffers 5.
    listen(srv_socket, 5);

    printf("\nServer.\nListening port: %d\n=======Start=======\n", PORT);

    while(1)
    {
        // Stop until accept a socket.
        clt_socket = accept(srv_socket, ptr_clt_addr, &clt_addr_size);
        if(0 > clt_socket)
        {
            printf("Accept socket error!\n");
            continue;
        }

        printf("\nReceive.\nIp: %s\nPort: %d\n", inet_ntoa(clt_addr.sin_addr), htons(clt_addr.sin_port));

        while(1)
        {
            datalen = read(clt_socket, buffer, sizeof(buffer));
            if(-1 == datalen)
            {
                printf("Read data error!\n");
                close(clt_socket);
                continue;
            }

            datalen = (BUFFER_SIZE <= datalen)?BUFFER_SIZE-1:datalen;
            buffer[datalen] = '\0';
            printf("\nMessage: %s\n", buffer);
            printf("-------End-------\n");

            if(0 == strcmp("quit", buffer))
            {
                close(clt_socket);
                break;
            }

            strcpy(reply_buff, REPLY_HEAD);
            ptr_reply_buff = reply_buff+strlen(reply_buff);
            strcpy(ptr_reply_buff, buffer);

            // reply the message.
            write(clt_socket, reply_buff, sizeof(reply_buff));
        }
    }
    close(srv_socket);

    return 0;
}
